/*
	datapath.v
	Datapath with register banks, ALU and corresponding special function registers.
	
	This project and file(s) are released under GNU GPL v3.
	Please find license file from root directory.
	Meng Sun (c) 2013 <leon.meng.sun@gmail.com>
*/

module datapath (GCLK, GnRESET, R0EN, R1EN, R2EN, R3EN, R4EN, R5EN, R6EN, R7EN, STACKEN, ALU0EN, ALU1EN, YEN, PSREN, MUXEXTREG, MUXREGALU, MUXARPSR, STACKMODE, FUNC, EXTREGInput, EXTREGOutput);

input GCLK, GnRESET; /*Clock and reset*/
input R0EN, R1EN, R2EN, R3EN, R4EN, R5EN, R6EN, R7EN;
input ALU0EN, ALU1EN;
input STACKEN;
input YEN, PSREN; /*Enablers*/
input [7:0] EXTREGInput; /*EXT input to register bank*/
input [5:0] MUXEXTREG; /*MUX from external to register bank*/
input [5:0] MUXREGALU; /*MUX from register bank to ALU or external*/
input MUXARPSR; /*MUX from register bank/ALU to PSR*/
input [3:0] FUNC; /*Function selector of ALU*/
input STACKMODE; /*Stack push or pop func selector*/

output [7:0] EXTREGOutput; /*EXT output from Register bank*/

wire GCLK, GnRESET; /*Clock and reset*/
wire R0EN, R1EN, R2EN, R3EN, R4EN, R5EN, R6EN, R7EN;
wire ALU0EN, ALU1EN;
wire YEN, PSREN; /*Enablers*/

wire [5:0] MUXEXTREG;
wire [7:0] EXTREGInput, Y;
wire ZR, OV, CB;
reg [7:0] R0i, R1i, R2i, R3i, R4i, R5i, R6i, R7i, TempRxi; /*Signals used by Mux from EXT to register bank*/

wire [5:0] MUXREGALU;
wire [7:0] R0, R1, R2, R3, R4, R5, R6, R7;
reg [7:0] TempRxo, EXTREGOutput, ALU0i, ALU1i; 
reg RBankOVUpdate, RBankCBoUpdate, RBankOV, RBankCBo, RBankZR; /*Signals used by Mux from register bank to EXT or ALU*/

wire [7:0] ALU0, ALU1; /*ALU register to ALU module*/
wire [7:0] ALUY; /*ALU module output Y to REGY*/

wire ALUOVUpdate, ALUOV, ALUCBoUpdate, ALUCBo, ALUZR; /*ALU module output to PSR*/
wire MUXARPSR;
reg PSROVUpdatei, PSROVi, PSRCBUpdatei, PSRCBi, PSRZRi; /*Signals used by Mux from ALU/RegBank to PSR register*/

reg [7:0] DStacki;
wire [7:0] DStacko; /*Signals used by Data Stack*/

always @ (MUXEXTREG or EXTREGInput or Y or ZR or OV or CB or EXTREGOutput or DStacko)
begin
	case ({MUXEXTREG[5], MUXEXTREG[4], MUXEXTREG[3]})
	3'b000: begin /*From EXT*/
		TempRxi = EXTREGInput;
	end
	3'b001: begin /*From Y*/
		TempRxi = Y;
	end
	3'b010: begin /*From PSR*/
		TempRxi = {ZR, OV, CB, 5'b0};
	end
	3'b011: begin /*From Rxo*/
		TempRxi = EXTREGOutput;
	end
	3'b100: begin /*From Data Stack*/
		TempRxi = DStacko;
	end
	default: begin
		TempRxi = 8'bx;
	end
	endcase

	case ({MUXEXTREG[2], MUXEXTREG[1], MUXEXTREG[0]})
	3'b000: begin
		R0i = TempRxi;
		R1i = 8'bx;
		R2i = 8'bx;
		R3i = 8'bx;
		R4i = 8'bx;
		R5i = 8'bx;
		R6i = 8'bx;
		R7i = 8'bx;
	end
	3'b001: begin
		R0i = 8'bx;
		R1i = TempRxi;
		R2i = 8'bx;
		R3i = 8'bx;
		R4i = 8'bx;
		R5i = 8'bx;
		R6i = 8'bx;
		R7i = 8'bx;
	end
	3'b010: begin
		R0i = 8'bx;
		R1i = 8'bx;
		R2i = TempRxi;
		R3i = 8'bx;
		R4i = 8'bx;
		R5i = 8'bx;
		R6i = 8'bx;
		R7i = 8'bx;
	end
	3'b011: begin
		R0i = 8'bx;
		R1i = 8'bx;
		R2i = 8'bx;
		R3i = TempRxi;
		R4i = 8'bx;
		R5i = 8'bx;
		R6i = 8'bx;
		R7i = 8'bx;
	end
	3'b100: begin
		R0i = 8'bx;
		R1i = 8'bx;
		R2i = 8'bx;
		R3i = 8'bx;
		R4i = TempRxi;
		R5i = 8'bx;
		R6i = 8'bx;
		R7i = 8'bx;
	end
	3'b101: begin
		R0i = 8'bx;
		R1i = 8'bx;
		R2i = 8'bx;
		R3i = 8'bx;
		R4i = 8'bx;
		R5i = TempRxi;
		R6i = 8'bx;
		R7i = 8'bx;
	end
	3'b110: begin
		R0i = 8'bx;
		R1i = 8'bx;
		R2i = 8'bx;
		R3i = 8'bx;
		R4i = 8'bx;
		R5i = 8'bx;
		R6i = TempRxi;
		R7i = 8'bx;
	end
	3'b111: begin
		R0i = 8'bx;
		R1i = 8'bx;
		R2i = 8'bx;
		R3i = 8'bx;
		R4i = 8'bx;
		R5i = 8'bx;
		R6i = 8'bx;
		R7i = TempRxi;
	end
	endcase
end

always @ (MUXREGALU or R0 or R1 or R2 or R3 or R4 or R5 or R6 or R7)
begin
	case ({MUXREGALU[5], MUXREGALU[4], MUXREGALU[3]})
	3'b000: begin
		TempRxo = R0;
	end
	3'b001: begin
		TempRxo = R1;
	end
	3'b010: begin
		TempRxo = R2;
	end
	3'b011: begin
		TempRxo = R3;
	end
	3'b100: begin
		TempRxo = R4;
	end
	3'b101: begin
		TempRxo = R5;
	end
	3'b110: begin
		TempRxo = R6;
	end
	3'b111: begin
		TempRxo = R7;
	end
	endcase
	
	case ({MUXREGALU[2], MUXREGALU[1], MUXREGALU[0]})
	3'b000: begin
		ALU0i = TempRxo;
		ALU1i = 8'bx;
		EXTREGOutput = 8'bx;
		RBankOVUpdate = 1'bx;
		RBankCBoUpdate = 1'bx;
		RBankZR = 1'bx;
		RBankOV = 1'bx;
		RBankCBo = 1'bx;
		DStacki = 8'bx;
	end
	3'b001: begin
		ALU0i = 8'bx;
		ALU1i = TempRxo;
		EXTREGOutput = 8'bx;
		RBankOVUpdate = 1'bx;
		RBankCBoUpdate = 1'bx;
		RBankZR = 1'bx;
		RBankOV = 1'bx;
		RBankCBo = 1'bx;
		DStacki = 8'bx;
	end
	3'b010: begin
		ALU0i = 8'bx;
		ALU1i = 8'bx;
		EXTREGOutput = TempRxo;
		RBankOVUpdate = 1'bx;
		RBankCBoUpdate = 1'bx;
		RBankZR = 1'bx;
		RBankOV = 1'bx;
		RBankCBo = 1'bx;
		DStacki = 8'bx;
	end
	3'b011: begin
		ALU0i = 8'bx;
		ALU1i = 8'bx;
		EXTREGOutput = 8'bx;
		RBankOVUpdate = 1'b1;
		RBankCBoUpdate = 1'b1;
		RBankZR = TempRxo[7];
		RBankOV = TempRxo[6];
		RBankCBo = TempRxo[5];
		DStacki = 8'bx;
	end
	3'b100: begin
		ALU0i = 8'bx;
		ALU1i = 8'bx;
		EXTREGOutput = 8'bx;
		RBankOVUpdate = 1'bx;
		RBankCBoUpdate = 1'bx;
		RBankZR = 1'bx;
		RBankOV = 1'bx;
		RBankCBo = 1'bx;
		DStacki = TempRxo;
	end
	default: begin
		ALU0i = 8'bx;
		ALU1i = 8'bx;
		EXTREGOutput = 8'bx;
		RBankOVUpdate = 1'bx;
		RBankCBoUpdate = 1'bx;
		RBankZR = 1'bx;
		RBankOV = 1'bx;
		RBankCBo = 1'bx;
		DStacki = 8'bx;
	end
	endcase
end

always @ (MUXARPSR or ALUCBo or ALUCBoUpdate or ALUOV or ALUOVUpdate or ALUZR or RBankCBo or RBankCBoUpdate or RBankOV or RBankOVUpdate or RBankZR)
begin
	case (MUXARPSR)
	1'b0: begin /*RegisterBank -> PSR*/
		PSRCBi = RBankCBo;
		PSRCBUpdatei = RBankCBoUpdate;
		PSROVi = RBankOV;
		PSROVUpdatei = RBankOVUpdate;
		PSRZRi = RBankZR;
	end
	1'b1: begin /*ALU -> PSR*/
		PSRCBi = ALUCBo;
		PSRCBUpdatei = ALUCBoUpdate;
		PSROVi = ALUOV;
		PSROVUpdatei = ALUOVUpdate;
		PSRZRi = ALUZR;
	end
	endcase
end

reg8 REG0 (.A(R0i), .CLK(GCLK), .nRESET(GnRESET), .EN(R0EN), .Y(R0));
reg8 REG1 (.A(R1i), .CLK(GCLK), .nRESET(GnRESET), .EN(R1EN), .Y(R1));
reg8 REG2 (.A(R2i), .CLK(GCLK), .nRESET(GnRESET), .EN(R2EN), .Y(R2));
reg8 REG3 (.A(R3i), .CLK(GCLK), .nRESET(GnRESET), .EN(R3EN), .Y(R3));
reg8 REG4 (.A(R4i), .CLK(GCLK), .nRESET(GnRESET), .EN(R4EN), .Y(R4));
reg8 REG5 (.A(R5i), .CLK(GCLK), .nRESET(GnRESET), .EN(R5EN), .Y(R5));
reg8 REG6 (.A(R6i), .CLK(GCLK), .nRESET(GnRESET), .EN(R6EN), .Y(R6));
reg8 REG7 (.A(R7i), .CLK(GCLK), .nRESET(GnRESET), .EN(R7EN), .Y(R7));

dstack DATASTACK (.CLK(GCLK), .nRESET(GnRESET), .Di(DStacki), .EN(STACKEN), .Mode(STACKMODE), .Do(DStacko));

reg8 REGALU0 (.A(ALU0i), .CLK(GCLK), .nRESET(GnRESET), .EN(ALU0EN), .Y(ALU0));
reg8 REGALU1 (.A(ALU1i), .CLK(GCLK), .nRESET(GnRESET), .EN(ALU1EN), .Y(ALU1));

alu MALU (.CLK(GCLK), .A(ALU0), .B(ALU1), .CBi(CB), .FUNC(FUNC), .nALURESET(GnRESET), .CBo(ALUCBo), .IsCBoUpdate(ALUCBoUpdate), .OV(ALUOV), .IsOVUpdate(ALUOVUpdate), .ZR(ALUZR), .Y(ALUY));

reg8 REGY (.A(ALUY), .CLK(GCLK), .nRESET(GnRESET), .EN(YEN), .Y(Y));

psr REGPSR (.OVi(PSROVi), .OVEN(PSROVUpdatei), .CBi(PSRCBi), .CBEN(PSRCBUpdatei), .ZRi(PSRZRi), .GEN(PSREN), .CLK(GCLK), .nRESET(GnRESET), .OVo(OV), .CBo(CB), .ZRo(ZR));

endmodule